#ifndef __DYNOBJ_H__
#define __DYNOBJ_H__

// Author: Zane Lu
// LastUpdate: 2010/09/16

//
// Usage:
// 1.
//	class someClass : public CDialog
//	{
//		DECLARE_OBJ_MAP(7); // 7 is the count of dialog items
//		afx_msg void OnMove( int, int );					// ON_WM_MOVE()
//		afx_msg void OnSize( UINT, int, int );				// ON_WM_SIZE()
//		afx_msg void OnGetMinMaxInfo(MINMAXINFO* lpMMI);	// ON_WM_GETMINMAXINFO()
//	}
// 2.
//	BEGIN_MESSAGE_MAP(someClass, CDialog)
//		ON_WM_MOVE()
//		ON_WM_SIZE()
//		ON_WM_GETMINMAXINFO()
//	END_MESSAGE_MAP()
// 3.
//	BOOL someClass::OnInitDialog()
//	{
//		BEGIN_OBJ_MAP(someClass);
//		OBJ_DEFINE(IDC_CB_DEVICES,   0, 100,   0,   0 );
//		OBJ_DEFINE(...);
//		...
//		END_OBJ_MAP(someClass);
//	}
// 4.
//	void someClass::OnMove( int x, int y )
//	{
//		SAVE_WINDOW_PLACEMENT(someClass);
//	}
//
//	void someClass::OnSize(UINT nType, int cx, int cy)
//	{
//		CDialog::OnSize(nType, cx, cy);
//		UPDATE_OBJ_POSITION(cx,cy);
//		SAVE_WINDOW_PLACEMENT(someClass);
//	}
//
//	void someClass::OnGetMinMaxInfo(MINMAXINFO* lpMMI)
//	{
//		UPDATE_MINMAX_INFO(lpMMI);
//		CDialog::OnGetMinMaxInfo(lpMMI);
//	}


// x is the number of the dialog items
#define DECLARE_OBJ_MAP(x) \
	OBJINFO _apObjInfo_[x]; \
	int _nObjCount_; \
	CRect m_rcInitialWindow; \
	CRect m_rcInitialClient;

#define BEGIN_OBJ_MAP(x) _nObjCount_ = 0

// x: id of a dialog item
// a: ratio of the left   border ( 0 - 100 )
// b: ratio of the right  border ( 0 - 100 )
// c: ratio of the top    border ( 0 - 100 )
// d: ratio of the bottom border ( 0 - 100 )
#define OBJ_DEFINE(x,a,b,c,d) \
	_apObjInfo_[_nObjCount_].id = x; \
	_apObjInfo_[_nObjCount_].x1frac = a; \
	_apObjInfo_[_nObjCount_].x2frac = b; \
	_apObjInfo_[_nObjCount_].y1frac = c; \
	_apObjInfo_[_nObjCount_].y2frac = d; \
	GetDlgItem(x)->GetWindowRect(&_apObjInfo_[_nObjCount_].rc); \
	ScreenToClient(&_apObjInfo_[_nObjCount_].rc); \
	_nObjCount_++

#define END_OBJ_MAP(x) \
	ASSERT(_nObjCount_ <= sizeof(_apObjInfo_)/sizeof(_apObjInfo_[0]) ); \
	GetClientRect(&m_rcInitialClient); \
	GetWindowRect(&m_rcInitialWindow); \
	UINT __x = AfxGetApp()->GetProfileInt(_T(#x),_T("WindowX"),m_rcInitialWindow.left); \
	UINT __y = AfxGetApp()->GetProfileInt(_T(#x),_T("WindowY"),m_rcInitialWindow.top); \
	UINT __w = AfxGetApp()->GetProfileInt(_T(#x),_T("WindowWidth"),m_rcInitialWindow.Width()); \
	UINT __h = AfxGetApp()->GetProfileInt(_T(#x),_T("WindowHeight"),m_rcInitialWindow.Height()); \
	MoveWindow( __x, __y, __w, __h, FALSE )

// cx: new width
// cy: new height
#define UPDATE_OBJ_POSITION(cx,cy) \
	if (GetDlgItem(_apObjInfo_[0].id) && GetDlgItem(_apObjInfo_[0].id)->GetSafeHwnd()) { \
		int __nDeltaX = cx - ( m_rcInitialClient.right - m_rcInitialClient.left ); \
		int __nDeltaY = cy - ( m_rcInitialClient.bottom - m_rcInitialClient.top ); \
		for ( int __i = 0; __i < _nObjCount_; __i++ ) { \
			OBJINFO* p = &_apObjInfo_[__i]; \
			RECT rcNew; \
			rcNew.left   = p->rc.left   + ( p->x1frac * __nDeltaX ) / 100; \
			rcNew.right  = p->rc.right  + ( p->x2frac * __nDeltaX ) / 100; \
			rcNew.top    = p->rc.top    + ( p->y1frac * __nDeltaY ) / 100; \
			rcNew.bottom = p->rc.bottom + ( p->y2frac * __nDeltaY ) / 100; \
			GetDlgItem(p->id)->MoveWindow( &rcNew, FALSE ); \
		} \
		Invalidate(); \
	}

#define UPDATE_MINMAX_INFO(lpMMI) \
	if (GetDlgItem(_apObjInfo_[0].id) && GetDlgItem(_apObjInfo_[0].id)->GetSafeHwnd()) { \
		lpMMI->ptMinTrackSize.x = m_rcInitialWindow.right - m_rcInitialWindow.left; \
		lpMMI->ptMinTrackSize.y = m_rcInitialWindow.bottom - m_rcInitialWindow.top; \
	}

#define SAVE_WINDOW_PLACEMENT(x) \
	if (GetDlgItem(_apObjInfo_[0].id) && GetDlgItem(_apObjInfo_[0].id)->GetSafeHwnd()) { \
		CRect __rc; \
		GetWindowRect(&__rc); \
		AfxGetApp()->WriteProfileInt(_T(#x),_T("WindowX"),__rc.left); \
		AfxGetApp()->WriteProfileInt(_T(#x),_T("WindowY"),__rc.top); \
		AfxGetApp()->WriteProfileInt(_T(#x),_T("WindowWidth"),__rc.Width()); \
		AfxGetApp()->WriteProfileInt(_T(#x),_T("WindowHeight"),__rc.Height()); \
	}


typedef struct OBJINFO
{
	int		id;
	RECT	rc;
	BYTE	x1frac;
	BYTE	x2frac;
	BYTE	y1frac;
	BYTE	y2frac;
} OBJINFO;



#endif